package org.jacoco.cli.internal.commands;

import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import com.ydx.aa76111.agent.logger.AgentLog;
import com.ydx.aa76111.agent.utils.JavaVersionUtils;
import org.jacoco.cli.internal.Command;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.StringArrayOptionHandler;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

public class Attach extends Command {

    @Option(name = "--pids",
            handler = StringArrayOptionHandler.class,
            usage = "需要attach的java进程号（不填写默认attach所有的）",
            metaVar = "<pids>")
    List<String> pids = new ArrayList<>();

    @Option(name = "--agentPath", usage = "agent jar包地址", required = true)
    String agentPath;

    @Option(name = "--options", usage = "agent启动参数", metaVar = "<options>", required = true)
    String options;

    @Override
    public String description() {
        return "Attach Agent的方式运行测试覆盖率";
    }

    @Override
    public int execute(PrintWriter out, PrintWriter err) throws Exception {
        AgentLog.info("pids: {}, agentPath: {}, options: {}", pids, agentPath, options);

        List<VirtualMachineDescriptor> needAttachDescriptors = getNeedAttachDescriptors();

        for (VirtualMachineDescriptor descriptor : needAttachDescriptors) {
            VirtualMachine virtualMachine = VirtualMachine.attach(descriptor);
            verifyJavaVersion(virtualMachine);
            attach(virtualMachine);
        }
        return 0;
    }

    private List<VirtualMachineDescriptor> getNeedAttachDescriptors() {
        return VirtualMachine.list().stream()
                .filter(descriptor -> pids.isEmpty() || pids.contains(descriptor.id()))
                .collect(Collectors.toList());
    }

    private void verifyJavaVersion(VirtualMachine virtualMachine) {
        try {
            Properties targetSystemProperties = virtualMachine.getSystemProperties();
            String targetJavaVersion = JavaVersionUtils.javaVersionStr(targetSystemProperties);
            String currentJavaVersion = JavaVersionUtils.javaVersionStr();
            if (targetJavaVersion != null && currentJavaVersion != null) {
                if (!targetJavaVersion.equals(currentJavaVersion)) {
                    AgentLog.warn("Current VM java version: {} do not match target VM java version: {}, attach may fail.",
                            currentJavaVersion, targetJavaVersion);
                    AgentLog.warn("Target VM JAVA_HOME is {}, arthas-boot JAVA_HOME is {}, try to set the same JAVA_HOME.",
                            targetSystemProperties.getProperty("java.home"), System.getProperty("java.home"));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void attach(VirtualMachine machine) {
        try {
            machine.loadAgent(agentPath, options);
        } catch (AgentLoadException | AgentInitializationException | IOException e) {
            e.printStackTrace();
        }
    }
}
